package com.example.annotation.aop;

import com.example.annotation.annotation.OpLog;
import com.example.annotation.enums.OpType;
import java.lang.reflect.Method;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

/**
 * @author: v_jxchi
 * @date: 2020/11/27 18:15
 * @description:
 */
@Aspect
@Component
public class OpLogAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(OpLogAspect.class);

    @Around("@annotation(com.example.annotation.annotation.OpLog)")
    public Object log(ProceedingJoinPoint pjp) throws Exception {
        Method method = ((MethodSignature)pjp.getSignature()).getMethod();
        OpLog opLog = method.getAnnotation(OpLog.class);
        Object response = null;
        try {
            response = pjp.proceed();
        } catch (Throwable throwable) {
            throw new Exception(throwable);
        }
        if (StringUtils.isNotBlank(opLog.opItemIdExpression())) {
            SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
            Expression expression = spelExpressionParser.parseExpression(opLog.opItemIdExpression());
            EvaluationContext context = new StandardEvaluationContext();
            Object[] args = pjp.getArgs();
            LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
            String[] parameterNames = discoverer.getParameterNames(method);
            if (parameterNames != null) {
                for (int i = 0; i < parameterNames.length; i++) {
                    context.setVariable(parameterNames[i], args[i]);
                }
            }
            if (response != null) {
                context.setVariable(response.getClass().getSimpleName(), response);
            }

            String itemId = String.valueOf(expression.getValue(context));
            // 执行日志记录
            handle(opLog.opType(), opLog.opItem(), itemId);
        }
        return response;
    }

    private void handle(OpType opType,  String opItem, String opItemId) {
        // 通过日志打印输出
        LOGGER.info("opType = " + opType.name() +",opItem = " +opItem + ",opItemId = " +opItemId);
    }
}
